/**
  ******************************************************************************
  * @file    main.c
  * @author  ashuai0110
  * @version V1.0
  * @date    2024-03-05
  * @brief   使用举例-xmodem
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "stm32f10x.h"
#include "usart_dma.h"
#include "tim.h"

#include "xmodem.h"

/* 私有宏定义-----------------------------------------------------------------*/
#define XMODEM_TX_RX_TEST               (1u) /* 0:测试发送 1:测试接收 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static uint8_t usart1DmaTxBuf[200]; /* 串口1dma发送缓存区 */
static uint8_t usart1DmaRxBuf[200]; /* 串口1dma接收缓存区 */

static xmodem_t xmodem; /* xmodem实例 */
static uint8_t xmodemBuf[1029]; /* xmodem数据缓存区 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/
void usart1_tx_en(uint8_t enState);


/**
  * @brief  定时器1中断函数
  */
void TIM1_UP_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) 
    {
        /* 组件计时节拍接口 */
        module_tick_inc(1);
        
        TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);
    }
}

/**
  * @brief  串口1中断
  */
void USART1_IRQHandler(void)
{
    /* 串口1空闲中断 */
    if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
    {
        USART1->SR;
        USART1->DR;
        
        /* 这里写接收处理 */
        xmodem_write_rx_buf(&xmodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf) - DMA_GetCurrDataCounter(DMA1_Channel5));
        /* dma重配置 */
        usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
    }
}

/**
  * @brief  串口1接收的dma中断
  */
void DMA1_Channel5_IRQHandler(void)
{
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC5) != RESET)
    {
        /* 这里写接收处理 */
        xmodem_write_rx_buf(&xmodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf));
        /* dma重配置 */
        usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
        
        DMA_ClearITPendingBit(DMA1_IT_TC5);
    }
}

/**
  * @brief  串口1发送的dma中断
  */
void DMA1_Channel4_IRQHandler(void)
{
    static uint16_t num;
    
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC4) != RESET)
    {
        /* 这里写读取发送内容的处理 */
        num = xmodem_read_tx_buf(&xmodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
        usart1_dma_tx_reconfig(num); /* dma重配置 */
        
        DMA_ClearITPendingBit(DMA1_IT_TC4);
    }
}

/**
  * @brief  串口发送前准备函数
  * 
  * @param  enState : 0失能 1使能
  *
  * @retval None
  */
void usart1_tx_en(uint8_t enState)
{
    if(enState)
    {
        /* 判断当前是否正在发送 发送完成标志置位则不是正在发送 */
        if(USART_GetFlagStatus(USART1, USART_FLAG_TC) != RESET)
        {
            uint16_t num;
            num = xmodem_read_tx_buf(&xmodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
            if(0 < num)
            {
                usart1_dma_tx_reconfig(num); /* dma重配置 */
            }
            else
            {
                DMA_Cmd(DMA1_Channel4, DISABLE); /* 关闭dma */
            }
        }
    }
    else
    {
        DMA_Cmd(DMA1_Channel4, DISABLE);
    }
}

/**
  * @brief  获取xmodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据缓冲区(需读出数据)
  *
  * @param  len       : 有效数据长度(包含填充内容0x1A)
  *
  * @retval None
  */
void xmodem_get_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    uint16_t lenTmp = *len;

    PRINT_LOG("xmodem packet num:%d, len:%d, data: ", packetNum, lenTmp);
    for(uint16_t i = 0; i < lenTmp; i++)
    {
        PRINT_LOG("%02X ", data[i]);
    }
    PRINT_LOG("\r\n");
}

/**
  * @brief  设置xmodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据存放区(需填充数据)
  *
  * @param  len       : 有效数据长度(不包含填充内容0x1A,组件自动填充)
  *
  * @retval None
  */
void xmodem_set_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    /* 用户自行计算数据量并在发送完全后给len赋值0 */
    if(packetNum > 100)
    {
        *len = 0;
    } /* 用户自行选择携带128或1024字节数据并将数据赋值给data */
    else
    {
        *len = 1024;
        memset((void *)data, packetNum + '0', 1024);
    }
}

/**
  * @brief  main
  */
int main(int argc, char *argv[])
{
    VERSION_LOG("example-xmodem", 1, 0, 0);
    
    /* 串口及其dma初始化 */
    usart1_dma_init_config(115200, usart1DmaTxBuf, sizeof(usart1DmaTxBuf), usart1DmaRxBuf, sizeof(usart1DmaRxBuf));
    /* 定时器初始化 1ms */
    tim1_init_config(100-1, 720-1);

    /* xmodem组件初始化 */
    xmodem_init(&xmodem, xmodemBuf, sizeof(xmodemBuf), usart1_tx_en, xmodem_get_packet_callback, xmodem_set_packet_callback, 1000, 2);
#if XMODEM_TX_RX_TEST
    /* 启动xmodem接收 */
    xmodem_rx_start(&xmodem, XMODEM_RX_FLAG_CRC);
#endif
    
    while(1)
    {
        static uint8_t ret;
#if XMODEM_TX_RX_TEST
        ret = xmodem_rx_poll(&xmodem); /* xmodem接收轮询处理 */
        if(RET_OK == ret)
        {
            DEBUG_LOG("xmodem rx success");
        }
        else if(RET_ERR == ret)
        {
            DEBUG_LOG("xmodem rx failed");
        }
        else if(RET_TIMEOUT == ret)
        {
            DEBUG_LOG("xmodem rx timeout");
        }
#else
        ret = xmodem_tx_poll(&xmodem); /* xmodem发送轮询处理 */
        if(RET_OK == ret)
        {
            DEBUG_LOG("xmodem tx success");
        }
        else if(RET_ERR == ret)
        {
            DEBUG_LOG("xmodem tx failed");
        }
        else if(RET_TIMEOUT == ret)
        {
            DEBUG_LOG("xmodem tx timeout");
        }
#endif
    }
}

